home *** CD-ROM | disk | FTP | other *** search
/ Nautilus 1992 July / Nautilus-3-8 / Nautilus-3-8.bin / Tools & Utilities / Techy Stuff / Development Environments ƒ / Perl 4.0.2 ƒ / SubLaunch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-19  |  8.7 KB  |  371 lines

  1. /*********************************************************************
  2. Project    :    SubLaunch        -    Call ToolServer
  3. File        :    SubLaunch.c        -    The code
  4. Author    :    Matthias Neeracher
  5. Started    :    06Dec91                                Language    :    MPW C/C++
  6. Modified    :    06Dec91    MN    
  7. Last        :    06Dec91
  8.  
  9. Copyright (c) 1991, 1992 Matthias Neeracher
  10.  
  11.     You may distribute under the terms of either the GNU General Public
  12.     License or the Artistic License, as specified in the README file.
  13.  
  14. *********************************************************************/
  15.  
  16. /* We need glue for Gestalt, but not for the rest of the stuff */
  17.  
  18. #include <GestaltEqu.h>
  19.  
  20. #define SystemSevenOrLater    1
  21.  
  22. #include "SubLaunch.h"
  23. #include "SignatureToApp.h"
  24. #include "UnixFiles.h"
  25.  
  26. #include <Processes.h>
  27. #include <AppleEvents.h>
  28. #include <CursorCtl.h>
  29. #include <Resources.h>
  30. #include <QuickDraw.h>
  31. #include <Folders.h>
  32. #include <Errors.h>
  33. #include <Script.h>
  34.  
  35. #include <string.h>
  36.  
  37. #define FAILOSERR(call)    if (err = call)    return err
  38. #define ToolServer    'MPSX'
  39.  
  40. /* The following stuff is adapted from Jens Peter Alfke's SignatureToApp code */
  41.  
  42. static OSErr ToolServerRunning(ProcessSerialNumber *psn)
  43. {
  44.     OSErr err;
  45.     ProcessInfoRec info;
  46.     
  47.     psn->highLongOfPSN = 0;
  48.     psn->lowLongOfPSN  = kNoProcess;
  49.     do    {
  50.         FAILOSERR(GetNextProcess(psn));
  51.         info.processInfoLength     = sizeof(info);
  52.         info.processName             = nil;
  53.         info.processAppSpec         = nil;
  54.         FAILOSERR(GetProcessInformation(psn,&info));
  55.     } while(info.processSignature != ToolServer);
  56.  
  57.     *psn = info.processNumber;
  58.     
  59.     return noErr;
  60. }
  61.  
  62. static OSErr GetSysVolume(short *vRefNum)
  63. {
  64.     long dir;
  65.     
  66.     return FindFolder(kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir);
  67. }
  68.  
  69.  
  70. static OSErr GetIndVolume(short index, short *vRefNum)
  71. {
  72.     OSErr             err;
  73.     ParamBlockRec     pb;
  74.     
  75.     pb.volumeParam.ioNamePtr     = nil;
  76.     pb.volumeParam.ioVolIndex     = index;
  77.     
  78.     FAILOSERR(PBGetVInfoSync(&pb));
  79.     
  80.     *vRefNum = pb.volumeParam.ioVRefNum;
  81.     
  82.     return noErr;
  83. }
  84.  
  85. static OSErr VolHasDesktopDB(short vRefNum, Boolean * hasDesktop)
  86. {
  87.     OSErr                         err;
  88.     HParamBlockRec             pb;
  89.     GetVolParmsInfoBuffer     info;
  90.     
  91.     pb.ioParam.ioNamePtr     = nil;
  92.     pb.ioParam.ioVRefNum     = vRefNum;
  93.     pb.ioParam.ioBuffer         = (Ptr)&info;
  94.     pb.ioParam.ioReqCount     = sizeof(GetVolParmsInfoBuffer);
  95.     
  96.     FAILOSERR(PBHGetVolParmsSync(&pb));
  97.  
  98.     *hasDesktop = (info.vMAttrib & (1 << bHasDesktopMgr))!=0;
  99.     
  100.     return noErr;
  101. }
  102.  
  103. static OSErr FindAppOnVolume(short vRefNum, FSSpec *file)
  104. {
  105.     OSErr     err;
  106.     DTPBRec     pb;
  107.     
  108.     /* Get Acess path to Desktop database on this volume */
  109.     
  110.     pb.ioVRefNum         = vRefNum;
  111.     pb.ioNamePtr         = nil;
  112.     FAILOSERR(PBDTGetPath(&pb));
  113.     
  114.     pb.ioIndex             = 0;
  115.     pb.ioFileCreator     = ToolServer;
  116.     pb.ioNamePtr         = file->name;
  117.     switch (err = PBDTGetAPPLSync(&pb))    {
  118.     case noErr:
  119.         file->vRefNum     = vRefNum;
  120.         file->parID     = pb.ioAPPLParID;
  121.     
  122.         return noErr;
  123.     case fnfErr:
  124.         return afpItemNotFound;                        /* Bug in PBDTGetAPPL            */
  125.     default:
  126.         return err;
  127.     }
  128. }
  129.  
  130. /* LaunchApplication in 32 bit everything environment    */
  131.  
  132. pascal OSErr WrappedLaunchApplication(const LaunchParamBlockRec *LaunchParams);
  133.  
  134. static OSErr LaunchIt(const FSSpecPtr fileSpec, ProcessSerialNumber *psn )
  135. {
  136.     OSErr                     err;
  137.     LaunchParamBlockRec     pb;
  138.     
  139.     pb.launchBlockID             = extendedBlock;
  140.     pb.launchEPBLength         = extendedBlockLen;
  141.     pb.launchFileFlags         = launchNoFileFlags;
  142.     pb.launchControlFlags    = launchContinue | launchNoFileFlags | launchDontSwitch;
  143.     pb.launchAppSpec             = fileSpec;
  144.     pb.launchAppParameters    = nil;
  145.     
  146.     FAILOSERR(WrappedLaunchApplication(&pb));
  147.  
  148.     *psn = pb.launchProcessSN;
  149.     
  150.     return noErr;
  151. }
  152.  
  153. /* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
  154. static OSErr LaunchToolServer(ProcessSerialNumber *psn)
  155. {
  156.     OSErr     err;
  157.     short     sysVRefNum, vRefNum, index;
  158.     FSSpec     file;
  159.     Boolean     hasDesktopDB;
  160.     
  161.     /* See if ToolServer is already running:                    */
  162.     err    = ToolServerRunning(psn);
  163.     
  164.     if    (err != procNotFound)
  165.         return err;
  166.     
  167.     /* Not running, try to launch it */
  168.     
  169.     FAILOSERR(GetSysVolume(&sysVRefNum));
  170.     vRefNum     = sysVRefNum;
  171.     for (index = 0; !err; err = GetIndVolume(++index,&vRefNum)) {
  172.         if (!index || vRefNum != sysVRefNum) {
  173.             FAILOSERR(VolHasDesktopDB(vRefNum,&hasDesktopDB));
  174.             if (hasDesktopDB)    
  175.                 switch (err = FindAppOnVolume(vRefNum, &file))    {
  176.                 case noErr:
  177.                     return LaunchIt(&file,psn);
  178.                 case afpItemNotFound:
  179.                     break;
  180.                 default:
  181.                     return err;
  182.                 }
  183.         }
  184.     }
  185.     switch (err)    {
  186.     case nsvErr:
  187.     case afpItemNotFound:
  188.         return fnfErr;
  189.     default:
  190.         return err;
  191.     }
  192. }
  193.  
  194. typedef enum {
  195.     dontKnow,
  196.     canRun,
  197.     cantRun
  198. } featureCheck;
  199.  
  200. static featureCheck    requiredFeatures    =    dontKnow;
  201.  
  202. #define HASBIT(bit) (answer&(1<<bit))
  203. #define GESTALT(sel) !Gestalt(sel, &answer)
  204.  
  205. OSErr ValidateFeatures()
  206. {
  207.     long answer;
  208.     
  209.     switch (requiredFeatures)    {
  210.     case canRun:
  211.         return noErr;
  212.     case cantRun:
  213.         return gestaltUnknownErr;
  214.     case dontKnow:
  215.         if (    GESTALT(gestaltAppleEventsAttr)                            && 
  216.                     HASBIT(gestaltAppleEventsPresent)                     &&
  217.                  GESTALT(gestaltFindFolderAttr)                            &&
  218.                     HASBIT(gestaltFindFolderPresent)                     &&
  219.                 GESTALT(gestaltOSAttr)                                        &&
  220.                     HASBIT(gestaltLaunchCanReturn)                        &&
  221.                     HASBIT(gestaltLaunchFullFileSpec)                    &&
  222.                     HASBIT(gestaltLaunchControl)                            &&
  223.                 GESTALT(gestaltFSAttr)                                        &&
  224.                     HASBIT(gestaltHasFSSpecCalls)
  225.         )
  226.             requiredFeatures    =    canRun;
  227.         else
  228.             requiredFeatures     =     cantRun;
  229.         
  230.         return ValidateFeatures();
  231.     }
  232. }
  233.  
  234. #define FAILOSERR(call)    if (err = call)    return err
  235.  
  236. /* Create a temporary file in the temp folder. 
  237. */
  238. OSErr    FSpMakeTempFile(FSSpec * desc)
  239. {
  240.     static int    id    =    0;
  241.  
  242.     OSErr            err;
  243.     
  244.     FAILOSERR(ValidateFeatures());
  245.     FAILOSERR(FindFolder(kOnSystemDisk, 'temp', true, &desc->vRefNum, &desc->parID));
  246.     
  247.     *((long *) desc->name)        =    '\007tmp';
  248.     
  249.     do {
  250.         desc->name[4]    =    id / 1000     % 10 + '0';
  251.         desc->name[5]    =    id / 100        % 10 + '0';
  252.         desc->name[6]    =    id / 10        % 10 + '0';
  253.         desc->name[7]    =    id             % 10 + '0';
  254.         
  255.         ++id;
  256.         
  257.         err = FSpCreate(desc, 'TEMP', 'TEXT', smSystemScript);
  258.     } while (err == dupFNErr);
  259.     
  260.     return err;
  261. }
  262.             
  263. pascal Boolean SubLaunchIdle(EventRecord * ev, long * sleep, RgnHandle *)
  264. {
  265.     SpinCursor(1);
  266.     
  267.     if (ev->what == kHighLevelEvent)
  268.         if (AEProcessAppleEvent(ev)) 
  269.             return true;
  270.         
  271.     *sleep    =    10;
  272.     
  273.     return false;
  274. }
  275.  
  276. static char * Fragments[] = {
  277.     "Directory \'",
  278.     "\'; Begin; ",
  279.     "; End<\'",
  280.     "\' >\'",
  281.     "\' │\'",
  282.     "\'",
  283.     "Dev:Null"
  284. };
  285.  
  286. #define BEGIN_TEXT    Fragments[0]
  287. #define DIRSET_TEXT    Fragments[1]
  288. #define END_TEXT        Fragments[2]
  289. #define STDOUT_TEXT    Fragments[3]
  290. #define STDERR_TEXT    Fragments[4]
  291. #define TERM_TEXT        Fragments[5]
  292. #define DEVNULL_TEXT    Fragments[6]
  293. #define DEVSTRING(dev)                     \
  294.     if (dev)                                 \
  295.         segment = FSp2FullPath(dev);     \
  296.     else                                         \
  297.         segment = DEVNULL_TEXT
  298.         
  299. /* Execute the command. Any of the files may be set to NULL */
  300. OSErr SubLaunch(char * commandline, FSSpec * input, FSSpec * output, FSSpec * error)
  301. {
  302.     OSErr                        err;
  303.     Boolean                    same;
  304.     ProcessSerialNumber    psn;
  305.     ProcessSerialNumber    me;
  306.     AppleEvent                cmd;
  307.     AppleEvent                reply;
  308.     AEAddressDesc            addr;
  309.     acurHandle                acur;
  310.     Handle                    text;
  311.     char *                    segment;
  312.     FSSpec                    vol;
  313.     
  314.     /* Check if the system is sexy enough */
  315.     FAILOSERR(ValidateFeatures());
  316.     
  317.     /* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
  318.     FAILOSERR(LaunchToolServer(&psn));
  319.     
  320.     /* It would be disastrous to send the event to ourselves (I know: I tried) */
  321.     FAILOSERR(GetCurrentProcess(&me));
  322.     FAILOSERR(SameProcess(&psn, &me, &same));
  323.     if (same)
  324.         return appMemFullErr;            /* This is a lie. So what ? */
  325.     
  326.     /* Build shell wrapper for command string */
  327.     FAILOSERR(PtrToHand(BEGIN_TEXT, &text, strlen(BEGIN_TEXT)));
  328.     FAILOSERR(Path2FSSpec(":", &vol));
  329.     segment    =    FSp2FullPath(&vol);
  330.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  331.     FAILOSERR(PtrAndHand(DIRSET_TEXT, text, strlen(DIRSET_TEXT)));
  332.     FAILOSERR(PtrAndHand(commandline, text, strlen(commandline)));
  333.     FAILOSERR(PtrAndHand(END_TEXT, text, strlen(END_TEXT)));
  334.     DEVSTRING(input);
  335.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  336.     FAILOSERR(PtrAndHand(STDOUT_TEXT, text, strlen(STDOUT_TEXT)));
  337.     DEVSTRING(output);
  338.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  339.     FAILOSERR(PtrAndHand(STDERR_TEXT, text, strlen(STDERR_TEXT)));
  340.     DEVSTRING(error);
  341.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  342.     FAILOSERR(PtrAndHand(TERM_TEXT, text, strlen(TERM_TEXT)));
  343.     
  344.     /* Build the AppleEvent */
  345.     FAILOSERR(
  346.         AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(psn), &addr));
  347.     FAILOSERR(
  348.         AECreateAppleEvent('misc', 'dosc', &addr, 
  349.             kAutoGenerateReturnID, kAnyTransactionID, 
  350.             &cmd));
  351.     HLock(text);
  352.     FAILOSERR(
  353.         AEPutParamPtr(&cmd, '----', typeChar, *text, GetHandleSize(text)));
  354.     DisposHandle(text);
  355.     
  356.     /* Send it */
  357.     acur    =    (acurHandle) GetResource('acur', 128);
  358.     DetachResource((Handle) acur);
  359.     InitCursorCtl(acur);
  360.     err    =    
  361.         AESend(
  362.             &cmd, &reply, kAEWaitReply+kAENeverInteract, 
  363.             kAENormalPriority, kNoTimeOut, 
  364.             (IdleProcPtr) SubLaunchIdle, nil);
  365.     InitCursorCtl(NULL);
  366.     
  367.     return err;
  368. }
  369.  
  370.  
  371.